package org.jsola.hr.service.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsola.admin.vo.AreaReduceVO;
import org.jsola.common.BeanKit;
import org.jsola.common.DateKit8;
import org.jsola.hr.constant.FieldType;
import org.jsola.hr.entity.CompanyDO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.FormGroupFieldDO;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.query.HrUserQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.HrUserVO;
import org.jsola.user.core.TokenUser;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lyh
 */
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class TreatmentDisposeEventListener extends BaseAnalysisEventListener<Map<Integer, String>> {

    /**
     * 模板Id
     */
    private String templateId;

    /**
     * 当前用户
     */
    private TokenUser tokenUser;

    /**
     * List最大盛装数据条数
     */
    private static final Integer MAX_COUNT = 2000;

    /**
     * 表头为复合表头,第三行开始,表头才为最终表头
     */
    private int headIndex = 2;

    /**
     * excel导入总数
     */
    private Integer allCount = 0;

    /**
     * 导入总数中失败的数量
     */
    private Integer errorCount = 0;

    /**
     * 常量"接单时间"
     */
    private static final String TAKE_ORDERS_DATE = "接单时间";

    /**
     * 常量"接单客服"
     */
    private static final String TAKE_ORDERS_USER_NAME = "接单客服";

    /**
     * 常量"所属用工单位"
     */
    private static final String COMPANY_NAME = "所属用工单位";

    /**
     * 常量"员工姓名"
     */
    private static final String EMP_NAME = "姓名";

    /**
     * 常量"员工身份证号"
     */
    private static final String EMP_ID_CARD = "身份证号";

    /**
     * 常量 "50"
     */
    private static final Integer FIFTY = 50;

    /**
     * 常量 "200"
     */
    private static final Integer TWO_HUNDRED = 200;

    /**
     * 常量 "200"
     */
    private static final String COMMA = ",";

    /**
     * 模板字段
     */
    Map<String, FormGroupFieldDO> templateFieldMap;

    /**
     * 表头
     */
    Map<Integer, String> headMap;

    /**
     * 未校验的数据列表
     */
    List<Map<String, String>> checkDataList = new ArrayList<>();

    /**
     * 错误数据列表
     */
    List<Map<String, String>> errorList = new ArrayList<>();

    /**
     * 入库的数据列表
     */
    List<Map<String, String>> saveList = new ArrayList<>();

    /**
     * 地区
     */
    Map<String, AreaReduceVO> areaMap = new HashMap<>();

    /**
     * 模板的所有表头
     */
    List<String> fieldList = new ArrayList<>();

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        allCount++;
        // 改变一下data的数据结构
        Map<String, String> newData = new LinkedHashMap<>(32);
        for (Integer index : headMap.keySet()) {
            String headName = headMap.get(index);
            String value = data.get(index);
            newData.put(headName, value);
        }
        checkDataList.add(newData);
        if (checkDataList.size() >= MAX_COUNT) {
            // 入库
            saveData();
            // 存储完成清理 list
            checkDataList.clear();
            saveList.clear();
        }
    }

    @Override
    public void saveData() {
        // 校验错误数据
        this.checkError(checkDataList);
        ITreatmentDisposeEventService treatmentDisposeEventService = BeanKit
                .getBean(ITreatmentDisposeEventService.class);
        treatmentDisposeEventService.saveImport(saveList, templateFieldMap, templateId, tokenUser);
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        Integer rowIndex = context.readRowHolder().getRowIndex();
        // 复合表头,从第三行开始,表头最全
        if (headIndex == rowIndex) {
            // 拿到所有表头
            List<String> allHead = new ArrayList<>(headMap.values());
            this.headMap = headMap;
            // 必填表头
            List<String> necessaryList = new ArrayList<>();
            necessaryList.add("接单时间");
            necessaryList.add("接单客服");
            necessaryList.add("所属用工单位");
            necessaryList.add("姓名");
            necessaryList.add("身份证号");
            for (String necessaryField : necessaryList) {
                if (!allHead.contains(necessaryField)) {
                    throw new ExcelAnalysisException("请检查模板，缺少【" + necessaryField + "】表头");
                }
            }
            // 有三个字段是拼进去的 不在模板里面  这里手动把他加进去
            fieldList.add("接单时间");
            fieldList.add("接单客服");
            fieldList.add("所属用工单位");
            // 校验传进来的Excel的字段是否包含在模板字段中
            containsList(fieldList, allHead);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (!CollectionUtils.isEmpty(checkDataList)) {
            saveData();
            checkDataList.clear();
            saveList.clear();
        }

    }

    /**
     * 校验错误数据
     */
    private void checkError(List<Map<String, String>> dataList) {
        IUserProviderService userProviderService = BeanKit.getBean(IUserProviderService.class);
        ICompanyService companyService = BeanKit.getBean(ICompanyService.class);
        IEmpInfoService empInfoService = BeanKit.getBean(IEmpInfoService.class);
        IAdminProviderService adminProviderService = BeanKit.getBean(IAdminProviderService.class);
        List<AreaReduceVO> areaReduceList = adminProviderService.listAllArea();
        this.areaMap = areaReduceList.stream()
                .collect(Collectors.toMap(AreaReduceVO::getName, v -> v, (v1, v2) -> v1));
        // 前三列在模板中不存在,是拼到Excel里面的,需要提出来校验这三列
        for (Map<String, String> dataMap : dataList) {
            Map<String, String> dataMaoIterator = new HashMap<>(dataMap);
            StringBuilder errorInfo = new StringBuilder();
            String takeOrdersDate = dataMap.get(TAKE_ORDERS_DATE);
            String takeOrdersUserName = dataMap.get(TAKE_ORDERS_USER_NAME);
            String companyName = dataMap.get(COMPANY_NAME);
            String empName = dataMap.get(EMP_NAME);
            String empIdCard = dataMap.get(EMP_ID_CARD);
            String companyId = null;
            boolean empCheckFlag = false;
            for (String head : dataMaoIterator.keySet()) {
                String value = dataMap.get(head);
                if (!StringUtils.isEmpty(companyId) && !empCheckFlag) {
                    if (StringUtils.isEmpty(empName)) {
                        errorInfo.append("姓名：员工姓名为空");
                    }
                    if (StringUtils.isEmpty(empIdCard)) {
                        errorInfo.append("身份证号：员工身份证号为空");
                    }
                    if (!StringUtils.isEmpty(empName) && !StringUtils.isEmpty(empIdCard)) {
                        EmpInfoDO empInfo = empInfoService
                                .selectEmpByNameAndIdCard(empName, empIdCard, companyId, tokenUser);
                        if (ObjectUtils.isEmpty(empInfo)) {
                            errorInfo.append("姓名：未匹配到所属用工单位下的员工姓名")
                                    .append("身份证号：未匹配到所属用工单位下的员工身份证号");
                        } else {
                            dataMap.put("员工Id", empInfo.getId());
                        }
                    }
                    empCheckFlag = true;
                }
                if (TAKE_ORDERS_DATE.equals(head)) {
                    if (StringUtils.isEmpty(takeOrdersDate)) {
                        errorInfo.append("接单时间：为空;");
                    } else {
                        if (StringUtils.isEmpty(checkDate(value))) {
                            errorInfo.append("接单时间：格式有误，正确格式为2020-01-01;");
                        } else {
                            dataMap.put(head, checkDate(value));
                        }
                    }
                    continue;
                }
                if (TAKE_ORDERS_USER_NAME.equals(head)) {
                    if (StringUtils.isEmpty(takeOrdersUserName)) {
                        errorInfo.append("接单客服：为空;");
                    } else {
                        HrUserQuery hrUserQuery = new HrUserQuery();
                        hrUserQuery.setName(value);
                        List<HrUserVO> userList = userProviderService.queryUserList(hrUserQuery, tokenUser);
                        if (CollectionUtils.isEmpty(userList)) {
                            errorInfo.append("接单客服：未匹配到该管理员账号;");
                        } else {
                            dataMap.put("接单客服Id", userList.get(0).getId());
                        }
                    }
                    continue;
                }
                if (COMPANY_NAME.equals(head)) {
                    if (StringUtils.isEmpty(companyName)) {
                        errorInfo.append("所属用工单位：为空;");
                    } else {
                        CompanyDO company = companyService.selectByName(value, tokenUser.getSiteId());
                        if (ObjectUtils.isEmpty(company)) {
                            errorInfo.append("所属用工单位：未匹配到已存在的用工单位;");
                        } else {
                            companyId = company.getId();
                            dataMap.put("所属用工单位Id", company.getId());
                        }
                    }
                    continue;
                }
                FormGroupFieldDO formGroupField = templateFieldMap.get(head);
                this.checkFieldTypeAndValue(head, errorInfo, formGroupField, value, dataMap);
            }
            String errorInfoMsg = errorInfo.toString();
            if (!StringUtils.isEmpty(errorInfoMsg)) {
                errorCount++;
                dataMap.put("错误信息", errorInfoMsg);
                errorList.add(dataMap);
            } else {
                saveList.add(dataMap);
            }
        }
    }

    /**
     * 校验字段类型和内容是否相匹
     */
    private void checkFieldTypeAndValue(String head, StringBuilder errorInfo, FormGroupFieldDO field,
                                        String value, Map<String, String> dataMap) {
        // 手机性别  在导入的时候  不做必填校验
        List<String> notCheck = Arrays.asList("手机号", "性别", "工作地点");
        if (field.getIsNecessary() && StringUtils.isEmpty(value) && !notCheck.contains(head)) {
            errorInfo.append(field.getFieldName()).append("：为空");
        }
        Integer fieldType = field.getFieldType();
        if (FieldType.DROP_DOWN.getValue().equals(fieldType)) {
            // 校验下拉框
            String options = field.getOptions();
            if (checkDropDown(value, Arrays.asList(options.split(COMMA)))) {
                errorInfo.append(field.getFieldName()).append("：未匹配到该选择项;");
            }
        } else if (FieldType.DATE_SELECTION.getValue().equals(fieldType)) {
            // 校验时间
            if (!StringUtils.isEmpty(value)) {
                if (StringUtils.isEmpty(checkDate(value))) {
                    errorInfo.append(field.getFieldName()).append("：格式错误:正确格式参考2020/1/1;");
                } else {
                    dataMap.put(head, checkDate(value));
                }
            }
        } else if (FieldType.DATE2_SELECTION.getValue().equals(fieldType)) {
            // 校验时间
            if (!StringUtils.isEmpty(value)) {
                if (StringUtils.isEmpty(checkDate(value))) {
                    errorInfo.append(field.getFieldName()).append("：格式错误:正确格式参考2020/1;");
                } else {
                    dataMap.put(head, checkDate(value));
                }
            }
        } else if (FieldType.SINGLE_LINE_OF_TEXT.getValue().equals(fieldType)) {
            //多行输入框
            if (!StringUtils.isEmpty(value) && value.length() > TWO_HUNDRED) {
                errorInfo.append(field.getFieldName()).append("：不可超过200个字符;");
            }
        } else if (FieldType.SINGLE_LINE_TEXT.getValue().equals(fieldType)) {
            // 单行输入框
            if (!StringUtils.isEmpty(value) && value.length() > FIFTY) {
                errorInfo.append(field.getFieldName()).append("：不可超过50个字符;");
            }
        } else if (FieldType.MULTIPLE_LINE_TEXT.getValue().equals(fieldType)) {
            // 数字输入框
            if (!StringUtils.isEmpty(value)) {
                if (checkNum(value)) {
                    errorInfo.append(field.getFieldName()).append("格式错误，请输入数字;");
                } else if (value.length() > FIFTY) {
                    errorInfo.append(field.getFieldName()).append("不可超过50个数字;");
                }
            }
        } else if (FieldType.REGION.getValue().equals(fieldType)) {
            if (!StringUtils.isEmpty(value)) {
                if (checkArea(head, value, fieldType, dataMap)) {
                    errorInfo.append(field.getFieldName()).append("格式错误:正确格式请参考,山东/青岛/市北区;");
                }
            }
        } else if (FieldType.REGION_TWO.getValue().equals(fieldType)) {
            if (!StringUtils.isEmpty(value)) {
                if (checkArea(head, value, fieldType, dataMap)) {
                    errorInfo.append(field.getFieldName()).append("格式错误:正确格式请参,考山东/青岛;");
                }
            }
        }
    }

    /**
     * 校验下拉框
     */
    private Boolean checkDropDown(String value, List<String> dropDownList) {
        if (StringUtils.isEmpty(value)) {
            return false;
        } else {
            return CollectionUtils.isEmpty(dropDownList) || !dropDownList.contains(value);
        }
    }

    /**
     * 校验地区
     */
    private Boolean checkArea(String head, String value, Integer fieldType, Map<String, String> dataMap) {
        StringBuilder areaFormat = new StringBuilder();
        String[] splitArea = value.split("/");
        for (int i = 0; i < splitArea.length; i++) {
            String areaStr = splitArea[i];
            if (FieldType.DETAILED_ADDRESS.getValue().equals(fieldType) && i == splitArea.length - 1) {
                if (splitArea.length != 1) {
                    areaFormat.append(",");
                }
                areaFormat.append("d_").append(areaStr);
                dataMap.put(head, areaFormat.toString());
                return false;
            }
            if (areaStr.contains("省") || areaStr.contains("市")) {
                areaStr = areaStr.substring(0, areaStr.length() - 1);
            }
            AreaReduceVO areaReduce = areaMap.get(areaStr);
            if (ObjectUtils.isEmpty(areaReduce)) {
                return true;
            }
            areaFormat.append(areaReduce.getId()).append("_").append(areaStr);
            if (i != splitArea.length - 1) {
                areaFormat.append(",");
            }
        }
        dataMap.put(head, areaFormat.toString());
        return false;
    }

    /**
     * 校验日期
     */
    private String checkDate(String value) {
        if (!StringUtils.isEmpty(value)) {
            String dateStr;
            try {
                value = value.replace("/", "-");
                String[] dateArray = value.split("-");
                // 可能有三个  可能有两个   分别是 年月日  或者 年月
                String month = dateArray[1];
                if (month.length() == 1) {
                    month = "0" + month;
                }
                String day;
                if (dateArray.length == 2) {
                    day = "01";
                } else {
                    day = dateArray[2];
                    if (day.length() == 1) {
                        day = "0" + day;
                    }
                }
                dateStr = dateArray[0] + "-" + month + "-" + day;
                DateKit8.parseDate(dateStr);
            } catch (Exception e) {
                return null;
            }
            return dateStr;
        }
        return null;
    }

    /**
     * 校验数字
     */
    private Boolean checkNum(String value) {
        if (!StringUtils.isEmpty(value)) {
            try {
                new BigDecimal(value);
            } catch (Exception e) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断一个List是否包含另一个List
     */
    private void containsList(List<String> bigList, List<String> smallList) {
        for (String field : smallList) {
            if (!bigList.contains(field)) {
                throw new ExcelAnalysisException("请检查模板，【" + field + "】在模板中不存在");
            }
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) {
        throw new ExcelAnalysisException(exception.getMessage());
    }
}
